using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Oops.Xna.Framework.GameState;

namespace Oops.Xna.Framework.UI
{
	public class UIComponent : DrawableGameComponent, IInternalUIService
	{
		private SpriteBatch spriteBatch;

		private Control activeControl;

		private bool initialized;
		private List<IGameComponent> notYetInitialized = new List<IGameComponent>();

		private ControlCollection controls;

		public UIComponent(Game game) : base(game)
		{
			// The game parameter must be specified.
			if (game == null)
			{
				throw new ArgumentNullException("game");
			}

			// Create the controls collection.
			this.controls = new ControlCollection(null);
			this.controls.ComponentAdded += new EventHandler<GameComponentCollectionEventArgs<Control>>(this.OnControlAdded);
			this.controls.ComponentRemoved += new EventHandler<GameComponentCollectionEventArgs<Control>>(this.OnControlRemoved);
		}

		#region GameComponent Members

		protected override void Dispose(bool disposing)
		{
			if (disposing)
			{
				lock (this)
				{
					// Remove self from the service container.
					if (this.Game.GetService<IUIService>(false) == this)
					{
						this.Game.RemoveService<IUIService>();
					}
				}
			}

			// Call inherited method.
			base.Dispose(disposing);
		}

		#endregion

		#region DrawableGameComponent Members

		protected override void LoadContent()
		{
			// Create the sprite batch;
			this.spriteBatch = new SpriteBatch(this.GraphicsDevice);

			// Call inherited method.
			base.LoadContent();
		}

		protected override void UnloadContent()
		{
			// Dispose of the sprite batch.
			if (this.spriteBatch != null)
			{
				this.spriteBatch.Dispose();
			}
			
			// Call inherited method.
			base.UnloadContent();
		}

		#endregion

		#region IInternalUIService Members

		SpriteBatch IInternalUIService.SpriteBatch
		{
			get { return this.spriteBatch; }
		}

		#endregion

		#region IUIService Members

		public Control ActiveControl
		{
			get { return this.activeControl; }
			set { this.activeControl = value; }
		}

		public ControlCollection Controls
		{
			get { return this.controls; }
		}

		#endregion

		#region IGameComponent Members

		public override void Initialize()
		{
			// Add self to the service container.
			this.Game.AddService<IUIService>(this);
			this.Game.AddService<IInternalUIService>(this);

			// Initialize all necessary behaviors.
			while (this.notYetInitialized.Count != 0)
			{
				this.notYetInitialized[0].Initialize();
				this.notYetInitialized.RemoveAt(0);
			}

			// Call inherited method.
			base.Initialize();

			// Set the initialized flag.
			this.initialized = true;
		}

		#endregion

		#region IUpdateable Members

		public override void Update(GameTime gameTime)
		{
			// Update all controls.
			for (int i = 0; i < this.controls.Count; i++)
			{
				if (this.controls[i].Enabled)
				{
					this.controls[i].Update(gameTime);
				}
			}

			// Call inherited method.
			base.Update(gameTime);
		}

		#endregion

		#region IDrawable Members

		public override void Draw(GameTime gameTime)
		{
			// Prepare all controls.
			for (int i = 0; i < this.controls.Count; i++)
			{
				this.controls[i].Prepare(gameTime);
			}

			// Draw all controls.
			this.spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);

			for (int i = 0; i < this.controls.Count; i++)
			{
				if (this.controls[i].Visible)
				{
					this.controls[i].Draw(gameTime);
				}
			}
			this.spriteBatch.End();

			// Call inherited method.
			base.Draw(gameTime);
		}

		#endregion

		private void OnControlAdded(object sender, GameComponentCollectionEventArgs<Control> e)
		{
			// Initialize or add the control to the initialization pending list.
			if (this.initialized)
			{
				e.Item.Initialize();
			}
			else
			{
				this.notYetInitialized.Add(e.Item);
			}
		}

		private void OnControlRemoved(object sender, GameComponentCollectionEventArgs<Control> e)
		{
			// Remove the control from the initialization pending list.
			if (!this.initialized)
			{
				this.notYetInitialized.Remove(e.Item);
			}
		}
	}
}